package com.cyy.service;

import com.cyy.operation.appium.*;
import com.cyy.utils.Common;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.offset.PointOption;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import java.io.File;
import java.net.MalformedURLException;
import java.util.*;

@Slf4j
@Service

@PropertySource(value = {"classpath:application.properties"})
public class AppiumService {
    @Autowired
    AndroidAppium androidAppium;
    @Autowired
    IOSAppium iosAppium;
    @Autowired
    AndroidADB androidADB;
    @Autowired
    IOSADB iosadb;
    @Autowired
    Common common;

    @Value("${appium.server.ip}")
    String serverip;
    @Value("${appium.server.port}")
    int serverport;
    @Value("${appium.android.path}")
    String android_install_pkg_path;
    @Value("${appium.ios.path}")
    String ios_install_pkg_path;

    int timeout_locate = 1000;
    Map<String, Object> driver_adb_map = new HashMap<>();
    boolean reload = Boolean.parseBoolean(System.getProperty("Repload"));


    /**
     * 驱动准备，当前只完成android系统的，ios尚未完成
     *
     * @return map对象,driver appium驱动, adb
     */
    public AppiumService installDriver(String platformName, String series) throws MalformedURLException {
        driver_adb_map.put(series+":platformName",platformName);
        if (platformName.equalsIgnoreCase("android")) {
            AndroidDriver androidDriver = installAndroidDriver(series, android_install_pkg_path, serverip, serverport);
            driver_adb_map.put(series+":install_pkg_path",String.format("%s/%s",common.get_project_path(),android_install_pkg_path));
            driver_adb_map.put(series+":driver",androidDriver);
            driver_adb_map.put(series+":adb", androidADB);
            driver_adb_map.put(series+":appium",androidAppium);
        } else if (platformName.equalsIgnoreCase("ios")) {
            driver_adb_map.put(series+":install_pkg_path",String.format("%s/%s",common.get_project_path(),ios_install_pkg_path));
            driver_adb_map.put(series+":adb", iosadb);
            driver_adb_map.put(series+":appium",iosAppium);
            // todo
        }
        return this;
    }

    /**
     * 挂断电话
     * @param series 设备序列号
     * @return
     */
    public AppiumService cancel_call(String series) {
        AbstractADB adb = this.get_adb(series);
        adb.cancel_phone(series);
        return this;
    }

    /**
     * 安装安装包
     * @param series 执行手机的序列号
     * @return
     */
    public AppiumService installApk(String series) {
        AbstractADB adb = this.get_adb(series);
        String platformName = this.get_platformName(series);
        if (platformName.equalsIgnoreCase("android")) {
            log.warn("软件是否重新安装:" + reload);

            String pkg = adb.get_package(String.format("%s/%s",common.get_project_path(),android_install_pkg_path));
            if (reload) {
                if (adb.is_app_installed(pkg, series)) {
                    uninstallApk(series);
                }
                adb.install(String.format("%s/%s",common.get_project_path(),android_install_pkg_path),series);
            }
        } else if (platformName.equalsIgnoreCase("ios")) {
            // todo ios实现
        }
        return this;
    }

    /**
     * 卸载安装包
     * @param series 执行机的序列号
     * @return
     */
    public AppiumService uninstallApk(String series) {
        String platformName = this.get_platformName(series);
        AbstractADB adb = this.get_adb(series);
        String path = get_install_pkg_path(series);
        if (platformName.equalsIgnoreCase("android")) {
            String aPackage = androidADB.get_package(path);
            if (reload) {
                log.warn("开始卸载安装包:" + aPackage);

                if (adb.is_app_installed(aPackage, series)) adb.uninstall_apk(aPackage, series);
            }
        } else if (platformName.equalsIgnoreCase("ios")) {
            // todo ios实现
        }

        return this;
    }

    /**
     * 获取系统的版本
     * @param series 设备的序列号
     * @return 设备的版本信息 eg: android 5.1
     */
    public String get_system_version(String series) {
        String platformName = this.get_platformName(series);
        AbstractADB adb = this.get_adb(series);
        String platform_version = adb.get_platform_version(series);
        return platformName+" " + platform_version;
    }

    /**
     * 获取设备制造商的名字
     * @param series 设备的序列号
     * @return 设备的名字 eg: GiONEE
     */
    public String get_product_brand(String series) {
        AbstractADB adb = this.get_adb(series);
        return adb.get_brand(series);
    }

    /**
     * 是否重新安装app
     *
     * @return 重新安装返回true，否则返回false
     */
    public boolean is_repload() {
        return reload;
    }


    /**
     * 删除执行机上的指定的文件
     *
     * @param path 执行机上的文件的路径
     * @return
     */
    public AppiumService rm_file(String path,String series) {
        AbstractADB adb = this.get_adb(series);
        adb.remove_file(path, series);
        return this;
    }

    public AppiumService rm_folder(String series) {
        String path = get_install_pkg_path(series);
        AbstractADB adb = this.get_adb(series);
        adb.remove_dir(path, series);
        return this;
    }


    /**
     * 截屏
     * @param path  截图的电脑保存的路径 eg:d:/scrren.png
     * @param series 手机的序列号
     * @return remotepath:执行机保存图片的地址,localpath:本地的保存地址,byte: 图片
     */
    public Map<String, Object> screen(String path,String series) {
        if (!driver_adb_map.containsKey(series+":platformName")) return null;
        String platformName = this.get_platformName(series);
        if (platformName.equalsIgnoreCase("android")) {
            return screen_android(path, series);
        } else if (platformName.equalsIgnoreCase("ios")) {
            // todo
        }
        return null;
    }


    /**
     * 手机截图
     *
     * @return map对象, remotepath:执行机保存图片的地址,localpath:本地的保存地址,byte: 图片.如果当前adb为空则返回null
     */
    private Map<String, Object> screen_android(String path,String series) {
        Map<String, Object> map = new HashMap<>();
        AbstractADB adb = this.get_adb(series);
        AbstractAppium appium = this.get_appium(series);
        if (adb == null || appium==null || series==null) return null;
        // 解析路径，获取文件的名字
        File file = new File(path);
        String name = file.getName();
        String appath = "/sdcard/" + name;
        adb.screen(appath, series);
        log.warn("截图在执行机的路径:" + appath);
        // 把文件从手机端copy到电脑
        AppiumDriver driver = this.get_driver(series);
        byte[] bytes = appium.pullFile(driver,appath);
        common.byte2image(bytes, path);
        map.put("byte", bytes);
        map.put("remotepath", appath);
        map.put("localpath", path);
        return map;
    }

    /**
     * 唤醒执行机，如果执行机当前为唤醒状态则不做操作
     */
    public AppiumService wake(String series) {
        AbstractADB adb = this.get_adb(series);
        boolean iswake = adb.is_awake(series);
        if (!iswake) {
            log.warn("执行机处于熄屏状态，打开 > " + series);
            adb.awake(series);
        }
        return this;
    }

    public AppiumService wake(String platformName,String series) {
        if (platformName.equalsIgnoreCase("android")) {
            boolean iswake = androidADB.is_awake(series);
            if (!iswake) {
                log.warn("执行机处于熄屏状态，打开 > " + series);
                androidADB.awake(series);
            }
        }

        return this;
    }

    /**
     * 查找元素
     *
     * @param by 元素定位方式
     * @return 如果查找到指定的元素返回找到的元素，否则返回null
     */
    public WebElement find_element_by(String series,By by) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        Object obj = appium.fluentWait(driver,ExpectedConditions.visibilityOfElementLocated(by),
                timeout_locate / 10, 100);
        if (obj == null) return null;
        WebElement el = (WebElement) obj;
        return el;
    }

    public List<WebElement> find_elemets_by(String series,By by) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        Object objs = appium.fluentWait(driver,ExpectedConditions.visibilityOfAllElementsLocatedBy(by),
                timeout_locate / 10, 100);
        if (objs == null) return new ArrayList<WebElement>();
        List<WebElement> els = (List<WebElement>) objs;
        return els;
    }

    public AppiumService click(String series,By by) {
        AbstractAppium appium = get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        WebElement el = (WebElement) appium.fluentWait(driver,ExpectedConditions.visibilityOfElementLocated(by),
                timeout_locate / 10, 100);
        el.click();
        return this;
    }

    /**
     * 获取对象在指定设备下的为知
     * @param series 设备序列号
     * @param by 元素定位
     * @return map对象, key包含startX,startY,endX,endY
     */
    public Map<String, Float> get_el_bounds(String series, By by) {
        WebElement el = this.find_element_by(series, by);
        if (el == null) return null;
        String bounds = el.getAttribute("bounds");
        // [447,268][573,301]
        // 解析元素位置
        int p11 = bounds.indexOf("[");
        int p12 = bounds.indexOf("]");
        int p21 = bounds.lastIndexOf("[");
        int p22 = bounds.lastIndexOf("]");

        String[] point1s = bounds.substring(p11+1, p12).split(",");
        String[] point2s = bounds.substring(p21+1, p22).split(",");

        Map<String, Float> point = new HashMap<>();
        point.put("startX",Float.parseFloat(point1s[0]));
        point.put("startY",Float.parseFloat(point1s[1]));
        point.put("endX",Float.parseFloat(point2s[0]));
        point.put("endY",Float.parseFloat(point2s[1]));

        return point;
    }


    /**
     * 双击元素
     *
     * @param by
     * @return
     */
    public AppiumService dbclick(String series,By by) {
        this.click(series,by).waituntil(series,1000).click(series,by);
        return this;
    }

    public AppiumService input(String series,By by, String s) {
        AppiumDriver driver = this.get_driver(series);
        AbstractAppium appium = this.get_appium(series);
        appium.sendKeys(driver,by, s);
        return this;
    }

    public AppiumService swipe_left(String series) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.swipe_left(driver,1000);
        return this;
    }

    public AppiumService swipe_right(String series) {

        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.swipe_right(driver,1000);
        return this;
    }

    public AppiumService swipe_top(String series) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.swipe_top(driver,1000);
        return this;
    }

    public AppiumService swipe_down(String series) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.swipe_down(driver,1000);
        return this;
    }

    /**
     * 从设备的一点滑动到另外一点
     * @param series 设备序列号
     * @param start_point 开始点
     * @param end_point 结束点
     * @param dur 点指点滑动花费的时间
     * @return
     */
    public AppiumService swipe(String series, PointOption start_point, PointOption end_point, int dur) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.swipe(driver, start_point, end_point,dur);
        return this;
    }

    /**
     * 以设备屏幕中心点为中心，半径为设备宽度的 1/4，环绕中心点画图
     * @param series 设备序列号
     * @param dur 两点之间滑动时间
     * @return
     */
    public AppiumService swipe_around_circle(String series,int dur) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        Dimension screen_size = appium.screen_size(driver);
        int width = screen_size.width;
        int height = screen_size.height;

        LinkedList<PointOption> points_circle = common.get_points_circle(width / 2, 2*height / 3, height / 4 , 8);
        Collections.shuffle(points_circle);
        appium.swipe(driver,points_circle,dur);
       return this;
    }

    /**
     * 在设备的屏幕上中心点点击
     * @param series 设备序列号
     * @return
     */
    public AppiumService click_screen(String series) {
        AppiumDriver driver = this.get_driver(series);
        AbstractAppium appium = this.get_appium(series);
        appium.click_center(driver,1000);
        return this;
    }

    /**
     * 指定设备是否连接
     *
     * @param series
     * @return
     */
    public boolean is_advice_connected(String series) {

        AbstractADB adb = this.get_adb(series);
        String advice = adb.get_advice(series);
        return advice != null && !advice.equals("");
    }

    public boolean is_advice_connected(String platformName,String series) {
        if (platformName.equalsIgnoreCase("android")) {
            String advice = androidADB.get_advice(series);
            return advice != null && !advice.equals("");
        }else if (platformName.equalsIgnoreCase("ios")){
            return false;
        }
        return false;
    }

    public boolean connect_advice(String series) {
        AbstractADB adb = this.get_adb(series);
        return adb.connect_advice(series);
    }

    public boolean connect_advice(String platformName,String series) {
        if (platformName.equalsIgnoreCase("android")) {
            return androidADB.connect_advice(series);
        }else if (platformName.equalsIgnoreCase("ios")){
            return iosadb.connect_advice(series);
        }
        return false;
    }

    /**
     * 等待指定时长
     *
     * @param mills 毫秒
     * @return
     */
    public AppiumService waituntil(String series,int mills) {
        try {
            AbstractAppium appium = this.get_appium(series);
            appium.sleep(mills);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this;
    }

    /**
     * 退出
     */
    public AppiumService quit(String series) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.quit(driver);
        return this;
    }

    public AppiumService close(String series) {
        AbstractAppium appium = this.get_appium(series);
        AppiumDriver driver = this.get_driver(series);
        appium.closeApp(driver);
        return this;
    }

    /**
     * 设置查找元素时的超时时长
     *
     * @param mills 超时时长，单位毫秒
     * @return
     */
    public AppiumService timeout(int mills) {
        this.timeout_locate = mills;
        return this;
    }

    public String get_cpu(String series) {

        AbstractADB adb = this.get_adb(series);
        String cpu_info = adb.get_cpu_info(series);
        return cpu_info;
    }

    public String get_memory_total(String series) {

        AbstractADB adb = this.get_adb(series);
        String memTotal = adb.getMemTotal(series).replace("MemTotal:", "")
                .replace(" ", "");

        return memTotal;
    }

    public String get_memory_free(String series) {
        AbstractADB adb = this.get_adb(series);
        String memfree = adb.getMemFree(series).replace("MemFree:", "")
                .replace(" ", "");

        return memfree;
    }

    private AndroidDriver installAndroidDriver(String series, String apk_path, String serverip, int serverport) throws MalformedURLException {

        String activity = androidADB.get_activity(apk_path);
        String pkg = androidADB.get_package(apk_path);
        try {
            AndroidDriver androidDriver = androidAppium.installDriver(series, androidADB.get_platform_version(series),
                    pkg, activity, serverip, serverport);
            return androidDriver;
        } catch (MalformedURLException e) {
            throw e;
        }
    }

    private AbstractADB get_adb(String series) {
        assert driver_adb_map.containsKey(series+":adb");
        return (AbstractADB) driver_adb_map.get(series+":adb");
    }

    private AbstractAppium get_appium(String series) {
        log.error("是否包含 "+ series+":appium" + "\t"+driver_adb_map.containsKey(series+":appium"));
        assert driver_adb_map.containsKey(series+":appium");
        return (AbstractAppium) driver_adb_map.get(series+":appium");
    }

    private String get_platformName(String series) {
        assert driver_adb_map.containsKey(series+":platformName");
        return (String) driver_adb_map.get(series+":platformName");
    }

    private AppiumDriver get_driver(String series) {
        assert driver_adb_map.containsKey(series+":driver");
        return (AppiumDriver) driver_adb_map.get(series+":driver");
    }

    private String get_install_pkg_path(String series) {
        assert driver_adb_map.containsKey(series+":install_pkg_path");
        return (String) driver_adb_map.get(series+":install_pkg_path");
    }

}
